Smart Pointer?
Same as C++ Smart,shared pointers, it allocates memory and deallocates
when all references to it goes out of scope. They only point to 1 value.
Examples: vec<T>, String.
Smart pointers are implemented using structs.
Interior mutability pattern
Interior mutability allows to mutate data even when there are immutable
references to that data;
Normally, changing the data inside immutable reference is not allowed by
Rust's borrowing rules.
But there are some cases eg(unsafe code) where we want to bend Rust’s
usual rules.
Types of Smart Pointers
Box <T>
Boxes allow to store data on the heap rather than the stack. Pointer is data is stored on stack and actual data on heap.
fn main() {
let b = Box::new(5);
println!("b = {b}");
}
Rc<T> (Reference Counted Pointer) / Shared pointer
Multiple owners of 1 pointer. It keeps track of the number of references
to a value to determine whether or not the value is still in use
If there are 0 references to a value, the value will be cleaned up
This is not thread safe by default
clone(): Invoking clone on Rc produces a new pointer to the same
allocation in the heap.
use std::rc::Rc;
struct Person {
name: String,
age: u8,
}
fn main() {
let person = Rc::new(Person {
name: String::from("Alice"),
age: 25,
});
println!("Name: {}", person.name); //Alice
println!("Age: {}", person.age); //25
let person_clone1 = person.clone();
let person_clone2 = person.clone();
println!("Number of owners: {}", Rc::strong_count(&person)); //3
drop(person_clone2);
println!("Number of owners: {}", Rc::strong_count(&person)); //2
drop(person_clone1);
println!("Number of owners: {}", Rc::strong_count(&person)); //1
}
Features
1. Mutable Reference
Shared references in Rust disallow mutation by default. You cannot
obtain a mutable reference to something inside an Rc
If you need mutability, put a Cell or RefCell inside the Rc
2. Thread Safe (No)
Reference counting done by Rc is non-atomic, Hence overhead is less(wrt
Arc<T> )
Rc does not implement
Send Trait
Rust compiler will check at compile time that you are not sending Rcs
between threads.
RefCell
It allows to implement interior mutability pattern,
allowing to mutate data even we have an immutable reference
The Rule:
Rust enforces its borrowing rules at compile time: we can have
either 1 mutable reference (&mut T) or any number of immutable
references (&T), but not both at the same time & this is checked at
compile time
With RefCell we move these borrowing checks from compile time to
runtime. runtime. It tracks borrows dynamically using an internal
counter. If you break the rules at runtime (e.g., trying to create two
mutable borrows at once), your program will panic and crash instead of
failing to compile